package com.github.data_manage.controller

import com.github.data_manage.common.CommonResult
import com.github.data_manage.common.ResultCode
import com.github.data_manage.config.SystemException
import com.github.data_manage.dao.*
import com.github.data_manage.domain.po.FundDepthResearch
import com.github.data_manage.domain.po.FundDepthResearchAttach
import com.github.data_manage.domain.po.FundDepthResearchAttachAnnualInfo
import com.github.data_manage.domain.po.FundDepthResearchAttachQuarterlyInfo
import com.github.data_manage.domain.vo.*
import com.github.data_manage.service.FundDeepResearchService
import com.github.data_manage.service.FundDepthResearchAttachImportService
import com.github.data_manage.service.FundDepthResearchAttachService
import com.github.data_manage.util.DateTimeUtils
import com.github.data_manage.util.mapAsyncBlocking
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.tags.Tag
import jakarta.servlet.http.HttpServletResponse
import jakarta.transaction.Transactional
import org.apache.poi.xssf.usermodel.XSSFWorkbook
import org.slf4j.LoggerFactory
import org.springframework.beans.BeanUtils
import org.springframework.core.io.ClassPathResource
import org.springframework.http.HttpHeaders
import org.springframework.http.MediaType
import org.springframework.transaction.support.TransactionTemplate
import org.springframework.web.bind.annotation.*
import org.springframework.web.multipart.MultipartFile
import java.net.URLEncoder
import java.nio.charset.StandardCharsets
import java.time.LocalDate

@RestController
@Tag(name = "FundDeppResearchController", description = "基金深度调研管理")
@RequestMapping("/fundDeepResearch")
class FundDepthResearchController(
    private val fundDeepResearchService: FundDeepResearchService,
    private val fundDao: FundDao,
    private val fundPersonDao: FundPersonDao,
    private val companyDao: CompanyDao,
    private val fundDepthResearchDao: FundDepthResearchDao,
    private val fundDepthResearchAttachDao: FundDepthResearchAttachDao,
    private val fundDepthResearchContrastAttachDao: FundDepthResearchContrastAttachDao,
    private val fundDepthResearchAttachService: FundDepthResearchAttachService,
    private val fundDepthResearchContrastAttachAnnualInfoDao: FundDepthResearchContrastAttachAnnualInfoDao,
    private val fundDepthResearchContrastAttachQuarterlyInfoDao: FundDepthResearchContrastAttachQuarterlyInfoDao,
    private val fundDepthResearchAttachAnnualInfoDao: FundDepthResearchAttachAnnualInfoDao,
    private val fundDepthResearchAttachQuarterlyInfoDao: FundDepthResearchAttachQuarterlyInfoDao,
    private val transactionTemplate: TransactionTemplate,
    private val fundDepthResearchAttachImportService: FundDepthResearchAttachImportService

) {

    companion object {

        private val logger = LoggerFactory.getLogger(this::class.java)

    }


    @PostMapping("/saveOrUpdate")
    @Operation(description = "新增/编辑基金深度调研信息")
    @Transactional(rollbackOn = [Exception::class])
    fun saveOrUpdate(@RequestBody fundDepthResearch: FundDepthResearch): CommonResult<String> {
        fundDeepResearchService.save(fundDepthResearch)
        return CommonResult.success(ResultCode.SUCCESS.message)
    }


    @Operation(description = "信息详情")
    @GetMapping(value = ["/details"])
    fun getPersonDetailsById(@RequestParam fundId: Int): CommonResult<FundDepthResearch?> {
        val fundDepthResearch: FundDepthResearch? = fundDeepResearchService.findByFundId(fundId)
        val fund = fundDao.findById(fundId).orElseThrow { SystemException("基金未找到") }

        var establishmentDate = fund.createDate?.let { DateTimeUtils.tryParse(it) };
        if (establishmentDate == null) {
            establishmentDate = LocalDate.now()
        }

        fundDepthResearch?.mons = fundDeepResearchService.calculateMons(establishmentDate);

        return if (fundDepthResearch != null) {
            fundDepthResearch.annReturn = fund.yearNav;
            CommonResult.success(fundDepthResearch)
        } else {
            CommonResult.success(FundDepthResearch(fundId))
        }
    }

    @Operation(description = "筛选导出基金深度调研信息")
    @PostMapping("/export")
    fun exportFundDepthResearch(
        servletResponse: HttpServletResponse,
        @RequestBody fundDepthResearchQueryVo: FundDepthResearchQueryVo
    ) {
        fundDeepResearchService.exportFundDepthResearch(fundDepthResearchQueryVo, servletResponse)
    }

    @Operation(description = "根据基金深度调研信息查询基金")
    @PostMapping("/list")
    fun listFundDepthResearch(
        @RequestBody fundDepthResearchQueryVo: FundDepthResearchQueryVo
    ): CommonResult<List<FundPageVo>> {
        val fundIds = fundDeepResearchService.listFundDepthResearch(fundDepthResearchQueryVo)
        return CommonResult.success(
            fundDao.findAllById(fundIds)
                .mapAsyncBlocking { fund ->
                    val fundPageVo = FundPageVo()
                    BeanUtils.copyProperties(fund, fundPageVo)
                    fundPageVo.fundCorePersons =
                        fundPersonDao.findAllByFundId(fund.fundId!!).filter { it.corePosition == true }
                            .map { FundCorePerson(it.personId!!, it.name!!) }
                    fund.companyId?.let { companyId ->
                        companyDao.findById(companyId).ifPresent { company ->
                            fundPageVo.companyCity = company.companyCity
                        }
                    }
                    fundPageVo.screenOverallRate =
                        fundDepthResearchDao.findByFundIdEquals(fund.fundId!!)!!.screenOverallRate
                    fundPageVo
                })

    }

    @GetMapping("/importAttachTemplate")
    @Operation(description = "下载基金深度调研导入文件")
    fun downloadFundDepthSearchTemplateFile(
        response: HttpServletResponse
    ) {
        response.contentType = MediaType.APPLICATION_OCTET_STREAM_VALUE
        response.characterEncoding = StandardCharsets.UTF_8.name()
        response.setHeader(
            HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + URLEncoder.encode(
                "深度调研导入模板.xlsx", StandardCharsets.UTF_8
            )
        )
        response.outputStream.use { os ->
            ClassPathResource("static/深度调研导入模板.xlsx").inputStream.use { inputStream -> inputStream.transferTo(os) }
        }
    }


    @PostMapping("/importAttachTemplate")
    @Operation(description = "上传基金深度调研导入文件")
    fun uploadFundDepthSearchAttach(
        @RequestParam fundId: Int,
        @RequestParam("excelFile") excelFile: MultipartFile
    ): CommonResult<Boolean?> {
        val fund = fundDao.findById(fundId).orElseThrow { SystemException("基金信息未找到") }
        val nonMatchExcelIndexNames = HashSet<String>()
        excelFile.inputStream.use { fis ->
            val workbook = XSSFWorkbook(fis)
            val fundDepthResearchAttachList = fundDepthResearchAttachImportService.loadAndSaveFundDepthResearchAttach(
                fundId,
                workbook,
                nonMatchExcelIndexNames
            )
            workbook.close()
            transactionTemplate.executeWithoutResult {
                fundDepthResearchAttachDao.saveAll(fundDepthResearchAttachList)
            }
        }
        Thread.startVirtualThread {
            logger.info("开始计算基金{}深度调研附加信息", fund.fundName)
            fundDepthResearchAttachService.handleAttachInfo(fund)
            logger.info("开始计算基金{}深度调研附加指数对比信息", fund.fundName)
            fundDepthResearchAttachService.handleContrastAttach(fund)
            logger.info("完成计算基金{}深度调研信息计算", fund.fundName)
        }

        if (nonMatchExcelIndexNames.isNotEmpty()) {
            return CommonResult.failed<Boolean>("列${nonMatchExcelIndexNames}未匹配到数据字段")
        }
        return CommonResult.success(true)
    }

    @GetMapping("/attachInfo")
    @Operation(description = "查询基金深度调研导入数据")
    fun getFundDepthSearchAttach(@RequestParam fundId: Int): CommonResult<List<FundDepthResearchAttach>> {
        val fundDepthResearchAttach =
            fundDepthResearchAttachDao.findAllByFundIdIs(fundId)
        return CommonResult.success(fundDepthResearchAttach)
    }

    @GetMapping("/attachQuarterlyInfo")
    @Operation(description = "基金深度调研季度数据")
    fun getFundDepthSearchAttachQuarterlyInfo(@RequestParam fundId: Int): CommonResult<List<FundDepthResearchAttachQuarterlyInfo>> {
        return CommonResult.success(fundDepthResearchAttachQuarterlyInfoDao.findAllByFundIdIs(fundId))
    }

    @GetMapping("/attachAnnualInfo")
    @Operation(description = "基金深度调研年化数据")
    fun getFundDepthSearchAttachAnnualInfo(@RequestParam fundId: Int): CommonResult<List<FundDepthResearchAttachAnnualInfo>> {
        return CommonResult.success(fundDepthResearchAttachAnnualInfoDao.findAllByFundId(fundId))
    }

    @PostMapping("/attachContrast")
    @Operation(description = "指数对比数据查询")
    fun attachContrast(@RequestBody batchFundDataQueryVo: BatchFundDataQueryVo): CommonResult<List<FundDepthResearchContrastVo<FundDepthResearchContrastValueVo>>> {
        val results = fundDepthResearchContrastAttachDao.findAllByFundIdIsAndContrastIdIn(
            batchFundDataQueryVo.baseFundId,
            batchFundDataQueryVo.contrastIds
        ).groupBy { it.fundId!! }.map { entry ->
            FundDepthResearchContrastVo(entry.key, entry.value.map {
                FundDepthResearchContrastValueVo(
                    it.threeMOutUnderPerf,
                    it.sixMOutUnderPerf,
                    it.twelveMOutUnderPerf,
                    it.thirtySixMOutUnderPerf,
                    it.twelveMRollBeta,
                    it.twelveMRollCorrel,
                    it.thirtySixMRollBeta,
                    it.thirtySixMRollCorrel
                )
            })
        }
        return CommonResult.success(results)
    }

    @PostMapping("/attachContrastQuarterlyInfo")
    @Operation(description = "基金深度调研季度数据")
    fun getFundDepthSearchContrastAttachQuarterlyInfo(@RequestBody batchFundDataQueryVo: BatchFundDataQueryVo): CommonResult<List<FundDepthResearchContrastVo<FundDepthResearchAttachQuarterlyValueInfo>>> {
        val results = fundDepthResearchContrastAttachQuarterlyInfoDao.findAllByFundIdIsAndContrastIdIn(
            batchFundDataQueryVo.baseFundId,
            batchFundDataQueryVo.contrastIds
        ).groupBy { it.fundId!! }.map { entry ->
            FundDepthResearchContrastVo(entry.key, entry.value.map {
                FundDepthResearchAttachQuarterlyValueInfo(
                    it.year,
                    it.quarter,
                    it.dataMonth,
                    it.alphaQuarterly,
                    it.betaQuarterly,
                    it.alphaLongQuarterly,
                    it.alphaShortQuarterly,
                    it.betaLongQuarterly,
                    it.betaShortQuarterly
                )
            })
        }
        return CommonResult.success(results)
    }


    @PostMapping("/attachContrastAnnualInfo")
    @Operation(description = "基金深度调研年化数据")
    fun getFundDepthSearchContrastAttachAnnualInfo(@RequestBody batchFundDataQueryVo: BatchFundDataQueryVo): CommonResult<List<FundDepthResearchContrastVo<FundDepthResearchAttachAnnualValueInfo>>> {
        val results = fundDepthResearchContrastAttachAnnualInfoDao.findAllByFundIdIsAndContrastIdIn(
            batchFundDataQueryVo.baseFundId,
            batchFundDataQueryVo.contrastIds
        ).groupBy { it.fundId!! }.map { entry ->
            FundDepthResearchContrastVo(entry.key, entry.value.map {
                FundDepthResearchAttachAnnualValueInfo(
                    it.year,
                    it.dataMonth,
                    it.alphaAnnual,
                    it.betaAnnual,
                    it.alphaLongAnnual,
                    it.alphaShortAnnual,
                    it.betaLongAnnual,
                    it.betaShortAnnual
                )
            })
        }
        return CommonResult.success(results)
    }

//    @PostMapping("/attachContrast")
//    @Operation(description = "指数对比数据查询")
//    fun attachContrast(@RequestBody batchFundDataQueryVo: BatchFundDataQueryVo): List<TimeDataVo<FundDepthResearchContrastValueVo>> {
//        return fundDepthResearchContrastAttachDao.findAllByFundIdIsAndContrastIdIn(
//            batchFundDataQueryVo.baseFundId,
//            batchFundDataQueryVo.contrastIds
//        ).groupBy { it.dataMonth!! }.map { entry ->
//            val time = entry.key
//            val values = entry.value.map {
//                val contrast = contrastDao.findById(it.contrastId!!).orElseThrow { SystemException("未找到对应的指数") }
//                FundDepthResearchContrastValueVo(
//                    contrast.id!!,
//                    contrast.name,
//                    it.threeMOutUnderPerf,
//                    it.sixMOutUnderPerf,
//                    it.twelveMOutUnderPerf,
//                    it.thirtySixMOutUnderPerf,
//                    it.twelveMRollBeta,
//                    it.twelveMRollCorrel,
//                    it.thirtySixMRollBeta,
//                    it.thirtySixMRollCorrel
//                )
//            }
//            TimeDataVo(time, values)
//        }
//    }

}
